package com.cgw.auth.advice;

import com.cgw.auth.annotation.Permission;
import com.cgw.auth.constance.AuthConst;
import com.cgw.auth.entity.AuthorizeInfo;
import com.cgw.auth.enumer.AuthRedisKey;
import com.cgw.auth.enumer.AuthStatus;
import com.cgw.auth.service.AuthorizeInfoService;
import jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.gavin.core.domain.R;
import org.gavin.core.enums.CommonStatus;
import org.redis.service.RedisService;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.List;

/**
 * AuthAdvice
 *
 * @author grl
 * @date 2022/4/21
 */
@Slf4j
@Aspect
@Component
@RequiredArgsConstructor
public class PermissionAdvice {

    private final RedisService redisService;
    private final HttpServletRequest request;
    private final AuthorizeInfoService authorizeInfoService;


    @Pointcut(value = "@annotation(com.cgw.auth.annotation.Permission)" +
            " && (@target(org.springframework.web.bind.annotation.RestController)" +
            " ||   @target(org.springframework.stereotype.Controller))")
    public void pointCut() {

    }

    @Around(value = "pointCut()")
    public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable {
        //通过获取Auth注解
        Method proxyMethod = ((MethodSignature) joinPoint.getSignature()).getMethod();
        Permission permission = proxyMethod.getAnnotation(Permission.class);
        if (permission != null) {
            String appId = request.getHeader(AuthConst.Header_APPID);
            if (StringUtils.isNotBlank(appId)) {
                return R.fail(CommonStatus.ACCESS_DENIED);
            }
            AuthRedisKey detailsKey = AuthRedisKey.AUTH_DETAILS;
            detailsKey.setKey(appId);
            AuthorizeInfo authorizeInfo = redisService.get(detailsKey, AuthorizeInfo.class);
            if (authorizeInfo == null) {
                authorizeInfo = authorizeInfoService.getAuth(appId);
            }
            if (authorizeInfo == null) {
                return R.fail(CommonStatus.ACCESS_DENIED);
            }
            // 检查权限
            String needScope = permission.scope();
            List<String> hasScope = Arrays.asList(authorizeInfo.getScope().split(","));
            if (!hasScope.contains(needScope)) {
                return R.fail(AuthStatus.NO_API_PERMISSION);
            }
            // 检查类型
            String needType = permission.accessType();
            String hasType = authorizeInfo.getAccessType();
            if(!AuthConst.ACCESS_ALL_TYPE.equals(hasType)){
                if(!needType.equals(hasType)){
                    return R.fail(AuthStatus.NO_TYPE_PERMISSION);
                }
            }
        }
        // 继续执行
        return joinPoint.proceed();
    }
}
